package Q10_07_Missing_Int; import java.io.*; import java.util.*; public class QuestionB { public static int findOpenNumber(String filename) throws FileNotFoundException { int rangeSize = (1 << 20); // 2^20 bits (2^17 bytes) /* Get count of number of values within each block. */ int[] blocks = getCountPerBlock(filename, rangeSize); /* Find a block with a missing value. */ int blockIndex = findBlockWithMissing(blocks, rangeSize); if (blockIndex < 0) return -1; /* Create bit vector for items within this range. */ byte[] bitVector = getBitVectorForRange(filename, blockIndex, rangeSize); /* Find a zero in the bit vector */ int offset = findZero(bitVector); if (offset < 0) return -1; /* Compute missing value. */ return blockIndex * rangeSize + offset; } /* Get count of items within each range. */ public static int[] getCountPerBlock(String filename, int rangeSize) throws FileNotFoundException { int arraySize = Integer.MAX_VALUE / rangeSize + 1; int[] blocks = new int[arraySize]; Scanner in = new Scanner (new FileReader(filename)); while (in.hasNextInt()) { int value = in.nextInt(); blocks[value / rangeSize]++; } in.close(); return blocks; } /* Find a block whose count is low. */ public static int findBlockWithMissing(int[] blocks, int rangeSize) { for (int i = 0; i < blocks.length; i++) { if (blocks[i] < rangeSize){ return i; } } return -1; } /* Create a bit vector for the values within a specific range. */ public static byte[] getBitVectorForRange(String filename, int blockIndex, int rangeSize) throws FileNotFoundException { int startRange = blockIndex * rangeSize; int endRange = startRange + rangeSize; byte[] bitVector = new byte[rangeSize/Byte.SIZE]; Scanner in = new Scanner(new FileReader(filename)); while (in.hasNextInt()) { int value = in.nextInt(); /* If the number is inside the block that's missing * numbers, we record it */ if (startRange <= value && value < endRange) { int offset = value - startRange; int mask = (1 << (offset % Byte.SIZE)); bitVector[offset / Byte.SIZE] |= mask; } } in.close(); return bitVector; } /* Find bit index that is 0 within byte. */ public static int findZero(byte b) { for (int i = 0; i < Byte.SIZE; i++) { int mask = 1 << i; if ((b & mask) == 0) { return i; } } return -1; } /* Find a zero within the bit vector and return the index. */ public static int findZero(byte[] bitVector) { for (int i = 0; i < bitVector.length; i++) { if (bitVector[i] != ~0) { // If not all 1s int bitIndex = findZero(bitVector[i]); return i * Byte.SIZE + bitIndex; } } return -1; } public static void generateFile(String filename, int max, int missing) throws FileNotFoundException { PrintWriter writer = new PrintWriter(filename); for (int i = 0; i < max && i >= 0; i++) { if (i != missing) { writer.println(i); } if (i % 10000 == 0) { System.out.println("Now at location: " + i); } } writer.flush(); writer.close(); } public static void main(String[] args) throws FileNotFoundException { String filename = "Ch 10. Scalability and Memory Limits/Q10_04_Missing_Int/input.txt"; int max = 10000000; int missing = 1234325; System.out.println("Generating file..."); generateFile(filename, max, missing); System.out.println("Generated file from 0 to " + max + " with " + missing + " missing."); System.out.println("Searching for missing number..."); System.out.println("Missing value: " + findOpenNumber(filename)); } }